package com.lhczf.lucenedb.util;

import com.lhczf.lucenedb.extend.scorer.EmptySimilarity;
import com.lhczf.lucenedb.service.LuceneDbServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.*;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.MMapDirectory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class LuceneUtil {
    public IndexWriter getIndexWriter(File indexDir) {
        Directory directory = getDirectory(indexDir);
        if (directory == null) return null;
        IndexWriter indexWriter = getIndexWriter(directory);
        if (indexWriter == null) return null;

        final Path docDir = Paths.get(indexDir.getAbsolutePath());
        if (!Files.isReadable(docDir)) {
            log.error("{}目录不存在或者没有访问权限，请检查。", docDir.toAbsolutePath());
            return null;
        }
        return indexWriter;
    }

    public Directory getDirectory(File indexDir) {
        Directory directory;
        try {
            directory = MMapDirectory.open(indexDir.toPath());
        } catch (IOException e) {
            log.error("创建索引的线程在打开索引目录:{}, 过程中出现异常:{}", indexDir.getAbsolutePath(), e);
            return null;
        }
        return directory;
    }

    public IndexWriter getIndexWriter(Directory directory) {
        Analyzer analyzer = getAnalyzer();
        IndexWriterConfig config = getIndexWriterConfig(analyzer);

        IndexWriter indexWriter;
        try {
            indexWriter = new IndexWriter(directory, config);
        } catch (IOException e) {
            log.error("在创建IndexWriter过程中出现异常:", e);
            return null;
        }
        return indexWriter;
    }

    public DirectoryTaxonomyWriter getTaxonmyWriter(String taxoDir) {
        File dir = new File(taxoDir);
        try {
            Directory directory = MMapDirectory.open(Paths.get(dir.getAbsolutePath()));
            DirectoryTaxonomyWriter writer = new DirectoryTaxonomyWriter(directory);
            writer.commit();
            return writer;
        } catch (IOException e) {
            log.error("", e);
        }
        return null;
    }

    public DirectoryTaxonomyReader getTaxonmyReader(String indexDir) {
        StringBuilder stringBuilder = new StringBuilder(indexDir);
        stringBuilder.append(File.separator).append(LuceneDbServer.ALL_INDEXS_DIR)
                .append(File.separator).append(LuceneDbServer.TAXONOMY_DIR_NAME);
        File dir = new File(stringBuilder.toString());
        try {
            Directory directory = MMapDirectory.open(Paths.get(dir.getAbsolutePath()));
            return new DirectoryTaxonomyReader(directory);
        } catch (IOException e) {
            log.error("", e);
        }
        return null;
    }

    public IndexWriterConfig getIndexWriterConfig(Analyzer analyzer) {
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
        String ramSize = SpringUtil.getProperValue("system.lucene.thread.ram");
        if (SpringUtil.haveLength(ramSize)) {
            config.setRAMBufferSizeMB(Integer.valueOf(ramSize));
        }
        config.setSimilarity(new EmptySimilarity());
        return config;
    }

    public Analyzer getAnalyzer() {
        return new SmartChineseAnalyzer();
    }

    public IndexSearcher makeCommSearcher() {

        IndexSearcher indexSearcher = null;
        try {
            IndexReader[] readers = getIndexReaders();
            MultiReader multiReader = new MultiReader(readers, true);
            indexSearcher = new IndexSearcher(multiReader);
            indexSearcher.setSimilarity(new EmptySimilarity());
        } catch (IOException e) {
            log.error("在构造MultiReader过程中出现异常。", e);
        }
        return indexSearcher;
    }

    public IndexReader[] getIndexReaders() {
        String indexDir = SpringUtil.getProperValue(LuceneDbServer.INDEX_ROOT_DIR);
        List<IndexReader> indexReaders = new ArrayList<>();
        File file = new File(indexDir);

        StringBuilder sb = new StringBuilder(file.getAbsolutePath());
        sb.append(File.separator).append(LuceneDbServer.ALL_INDEXS_DIR).append(File.separator).append("index");
        IndexReader otherIndex = openDirectory(new File(sb.toString()));
        if (otherIndex != null) {
            indexReaders.add(otherIndex);
        }

        String currentIndex = LocalDateTime.now().format(LuceneDbServer.Y_M_D_DTF);
        sb = new StringBuilder(file.getAbsolutePath());
        sb.append(File.separator).append(LuceneDbServer.INDEX_DAYS_DIR)
                .append(File.separator).append(currentIndex);
        openSubDir(indexReaders, sb);

        IndexReader[] readers = new IndexReader[indexReaders.size()];
        for (int i = 0; i < indexReaders.size(); i++) {
            readers[i] = indexReaders.get(i);
        }
        return readers;
    }

    private boolean openSubDir(List<IndexReader> indexReaders, StringBuilder sb) {
        List<File> dirs = FileUtils.findDirs(new File(sb.toString()));

        if (dirs.isEmpty()){
            log.error("索引目录异常，索引目录{}下没有数据文件。", sb.toString());
            return true;
        }
        for (int i = 0; i < dirs.size(); i++) {
            File dir = dirs.get(i);
            IndexReader indexReader = openDirectory(dir);
            if (indexReader != null) {
                indexReaders.add(indexReader);
            }
        }
        return false;
    }

    private IndexReader openDirectory(File dir) {
        IndexReader indexReader = null;
        try {
            Directory directory = MMapDirectory.open(dir.toPath());
            indexReader = DirectoryReader.open(directory);
        } catch (IndexNotFoundException e) {
            log.warn("{}目录下没有数据。", dir.getAbsolutePath());
        } catch (IOException e) {
            log.error("创建{}目录的Directory失败。", dir.getAbsolutePath(), e);
        }
        return indexReader;
    }
}
